package com.baiku.sanhos.controller;

import com.baiku.sanhos.mapper.AppointMapper;
import com.baiku.sanhos.mapper.BookingMapper;
import com.baiku.sanhos.mapper.RecordMapper;
import com.baiku.sanhos.mapper.SourceMapper;
import com.baiku.sanhos.pojo.dto.BookingDTO;
import com.baiku.sanhos.pojo.dto.RegisteredCancleDTO;
import com.baiku.sanhos.pojo.entity.*;
import com.baiku.sanhos.pojo.entity.Record;
import com.baiku.sanhos.pojo.vo.BookingRegisterVO;
import com.baiku.sanhos.pojo.vo.BookingVO;
import com.baiku.sanhos.pojo.vo.RequestBookingVo;
import com.baiku.sanhos.response.ResultVO;
import com.baiku.sanhos.response.StatusCode;
import com.baiku.sanhos.schedule.cache.BookingSchedule;
import com.baiku.sanhos.utils.RedisKeys;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.io.Serializable;
import java.util.*;
/**
 * @author ruoLi
 */
@Slf4j
@Api(tags = "预约管理")
@RestController
@Transactional
@RequestMapping("/pa/booking")
public class BookingController {
    @Autowired
    Booking booking;
    @Autowired
    BookingMapper bookingMapper;
    @Autowired
    SourceMapper sourceMapper;
    @Autowired
    AppointMapper appointMapper;
    @Autowired
    RecordMapper recordMapper;
    @Autowired
    RedisTemplate<String, Serializable> redisTemplate;
    @Autowired
    BookingSchedule bookingSchedule;
    /**
     * 用户预约数据
     *
     * @param bookingDTO 预约实体类
     * @return 返回结果
     * 一个用户一天最多只能预约两次，上午和下午
     * 加锁 防止并发情况
     */
    @ApiOperation("预约科室")
    @PostMapping("/registered")
    @PreAuthorize("hasAnyAuthority('Details')")
    public synchronized ResultVO booking(@RequestBody BookingDTO bookingDTO) {
        log.debug("接收客户端预约时间：【{}】", bookingDTO.getDate());
        BeanUtils.copyProperties(bookingDTO, booking);
        log.debug("封装的booking数据：{}",booking);
        //TODO 当前业务暂不处理 判断用户是否有预约记录
//        List<BookingVO> bookingList = bookingMapper.listDataBooking(booking.getUsername(), booking.getNickName());
//        if (bookingList.size()==0) {
            //code...
//        } else {
//            log.debug("用户预约数据：{}", bookingList);
            //查看数据库预约数据是否和当前预约时间有冲突  检查业务暂未处理
//        }
        //TODO 添加用户预约数据 开始
        Source surplus = sourceMapper.selectById(bookingDTO.getSourceId());
        log.debug("预约的号源数据：{}",surplus);
        if (surplus.getSourcesurplus() != 0) {
            //开始查询号源数量 号源数据-1
            Source source = new Source();
            UpdateWrapper<Source> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id",bookingDTO.getSourceId());
            source.setSourcesurplus(surplus.getSourcesurplus() - 1);
            //TODO 号源表剩余号源数据-1
            sourceMapper.update(source, updateWrapper);
            //开始查询排班号源数量 剩余号源-1
            Appoint appoint = appointMapper.selectById(surplus.getAppointId());
            Appoint appoint1=new Appoint();
            UpdateWrapper<Appoint> updateWrapperAppoint =  new UpdateWrapper<>();
            updateWrapperAppoint.eq("id",surplus.getAppointId());
            appoint1.setSourcesurplus(appoint.getSourcesurplus()-1);
            //TODO 排班表剩余号源数据-1
            appointMapper.update(appoint1,updateWrapperAppoint);
            //开始添加预约信息
            bookingMapper.insert(booking);
            log.info("预约成功!");
            return ResultVO.ok(StatusCode.BOOKING_SUCCESS);
        }
        log.warn("预约失败!");
        return ResultVO.error(StatusCode.BOOKING_FAILED);
    }

    //查询所有预约人的信息并且分页和查询
    @PostMapping("/selectAll")
    public ResultVO selectAll(@RequestBody RequestBookingData bookingData){
        int pageSize = bookingData.getPageSize();
        int page = bookingData.getPage();
        Map<String, Object> map = new HashMap<>();
        int total = bookingMapper.getTotalBooking(bookingData.getBookDoctorName(),bookingData.getNickname());//总条数
        int totalPages = (int)Math.ceil((double)total/pageSize);//计算总页数
        List<RequestBookingVo> booking;
        if(totalPages==0){
            booking = new ArrayList<>();
        }else {
            int offset = (page - 1) * pageSize;
            booking = bookingMapper.selectAll(pageSize,offset,bookingData.getBookDoctorName(),bookingData.getNickname());
        }
        map.put("booking", booking);
        map.put("total", total);
        return ResultVO.ok(map);
    }

    @PostMapping("/deleteByIds")
    @PreAuthorize("hasAuthority('AAA') or hasAuthority('DDD')")
    public ResultVO deleteByIds(@RequestBody List<Integer> ids){
        bookingMapper.deleteByIds(ids);
        return ResultVO.ok();
    }

    /**
     * 查询医生板块，当前登录的医生的患者
     * @param bookingData
     * @return
     */
    @PostMapping("/getDoctorSelectAll")
    public ResultVO getDoctorSelectAll(@RequestBody RequestBookingData bookingData){
        int pageSize = bookingData.getPageSize();
        int page = bookingData.getPage();
        Map<String, Object> map = new HashMap<>();
        int total = bookingMapper.getDoctorTotalBooking(bookingData.getBookDoctorName(),bookingData.getNickname(),bookingData.getDoctorNo());//总条数
        int totalPages = (int)Math.ceil((double)total/pageSize);//计算总页数
        List<RequestBookingVo> booking;
        if(totalPages==0){
            booking = new ArrayList<>();
        }else {
            int offset = (page - 1) * pageSize;
            booking = bookingMapper.selectDoctorAllUser(pageSize,offset,bookingData.getBookDoctorName(),bookingData.getNickname(),bookingData.getDoctorNo());
        }
        map.put("booking", booking);
        map.put("total", total);
        return ResultVO.ok(map);
    }

    @GetMapping("/updateByIdStatus/{id}")
    @PreAuthorize("hasAuthority('AAA')")
    public ResultVO updateByIdStatus(@PathVariable Integer id){
        RequestBookingVo bookingVo = bookingMapper.selectByIdBooking(id);
        if(bookingVo.getAppointmentStatus()==1 || bookingVo.getAppointmentStatus()==2){//已预约
            bookingMapper.updateByIdStatus(id);
            return ResultVO.ok();
        }else if(bookingVo.getAppointmentStatus()==3){
            return ResultVO.ok(StatusCode.CANCELLED_ERROR);
        }
        return ResultVO.ok(StatusCode.SEEN_SUCCESS);
    }

    @GetMapping("/updateById/{id}")
    @PreAuthorize("hasAuthority('DDD')")
    public ResultVO updateById(@PathVariable Integer id){
        RequestBookingVo bookingVo = bookingMapper.selectByIdBooking(id);
        if(bookingVo.getAppointmentStatus()==1){
            bookingMapper.updateById(id);
        }
        return ResultVO.ok();
    }

    @PostMapping("/addRecord")
    public ResultVO addRecord(@RequestBody Record record){
        int num = recordMapper.addRecord(record);
        if(num>0){
            Booking booking = new Booking();
            booking.setAppointmentStatus(4);
            UpdateWrapper updateWrapper = new UpdateWrapper();
            updateWrapper.eq("id",record.getId());
            bookingMapper.update(booking,updateWrapper);
        }
        return ResultVO.ok();
    }

    @ApiOperation("根据用户账号获取预约数据")
    @PreAuthorize("hasAnyAuthority('Details')")
    @GetMapping("/getBookingDataByUsername/{username}")
    public ResultVO getBookingData(@PathVariable String username){
        String key= RedisKeys.REDIS_KEYS_BOOKING.getValue()+":"+username;
        //读取缓存数据
        ListOperations<String, Serializable> listOperations = redisTemplate.opsForList();
        List<Serializable> list = listOperations.range(key, 0, -1);
        assert list != null;
        if (list.isEmpty()){
            return ResultVO.error(StatusCode.DATA_NOT_FOUND);
        }
        return ResultVO.ok(list);
    }

    @ApiOperation("用户取消预约")
    @PreAuthorize("hasAnyAuthority('Details')")
    @PostMapping("/registeredCancle")
    public ResultVO registeredCancle(@RequestBody RegisteredCancleDTO registeredCancleDTO){
        //更新缓存数据
        UpdateWrapper<Booking> wrapper=new UpdateWrapper<>();
        wrapper.eq("id",registeredCancleDTO.getId());
        wrapper.eq("username",registeredCancleDTO.getUsername());
        Booking booking=new Booking();
        booking.setAppointmentStatus(3);
        int status= bookingMapper.update(booking,wrapper);
        if (status!=0){
            //手动刷新缓存
            bookingSchedule.flushAllBookingData();
            String msg="取消成功";
            return ResultVO.ok(msg);
        }else {
            return ResultVO.error(StatusCode.OPERATION_FAILED);
        }
    }
    @ApiOperation("根据子用户id和状态查询预约数据")
    @PreAuthorize("hasAnyAuthority('Details')")
    @GetMapping("/searchByIdAndStatus/{patientsId}/{registeredStatus}")
    public ResultVO listSearchRegistered(@PathVariable String patientsId,@PathVariable Integer registeredStatus){
        //判断是否只包含数字
        if (patientsId.matches("^\\d+$")){
            List<BookingRegisterVO> bookingRegisterVOS = bookingMapper.listBookingRegisterByIdAndStatus(patientsId, registeredStatus);
            return ResultVO.ok(bookingRegisterVOS);
        }
        //如果没有选择子用户，就查询当前用户 如果是用户名
        List<BookingRegisterVO> bookingRegisterVOS= bookingMapper.listBookingRegisterByParentIdAndStatus(patientsId, registeredStatus);
        return ResultVO.ok(bookingRegisterVOS);
    }
}
